﻿#include "mediaDecode.h"
#include "decodeBase.h"
#include "ioQueue.h"
#include "decodeVideo.h"
#include "error.h"

#include <QVector>
#include <QDebug>

#include <crtdbg.h>
#include <assert.h>

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

class mediaDecodePrivate {
public:
    AVFormatContext *ic = NULL;
    ioQueue         *queue = NULL;

    QVector<decodeBase   *> decode;

    QVector<AVCodecContext*> cc;
    QVector<AVStream      *> s ;
    QVector<AVCodec       *> c ;
};

mediaDecode::mediaDecode(QObject *parent) :
    QObject(parent), d(new mediaDecodePrivate)
{
}

mediaDecode::~mediaDecode()
{
    stopDecode();
    delete d;
}

void mediaDecode::setIOQueue(ioQueue *queue)
{
    d->queue = queue;
}

void mediaDecode::setFormat(AVFormatContext *format)
{
    d->ic = format;
}

bool mediaDecode::startDecode()
{
    if (!openDecoder()) {
        return false;
    }
    return true;
}

void mediaDecode::stopDecode()
{
    if(d->decode.isEmpty())
        return ;

    for (auto &v: d->decode) {
        if (!v)
            continue;
        v->stopDecode();
        d->decode.removeOne(v);
        delete v;
    }
    d->decode.clear();

    for (int i = 0; i < d->cc.size(); i++) {
        if(d->cc[i] == NULL)
            continue;
        avcodec_close(d->cc[i]);
        d->cc[i] = NULL;
    }
    d->c.clear();
    d->s.clear();
    d->cc.clear();
}

bool mediaDecode::openDecoder()
{
    int nb_streams = d->ic->nb_streams;

    d->s.resize(nb_streams);
    d->c.resize(nb_streams);
    d->cc.resize(nb_streams);
    d->decode.resize(nb_streams);

    for(int i = 0; i < nb_streams; i++) {
		if (NULL == (d->s[i] = d->ic->streams[i])) {
			_errstr = "流为空";
			return false;
		}
		if (NULL == (d->cc[i] = d->ic->streams[i]->codec)) {
            _errstr  = "编码解码器上下文为空";
			return false;
		}
		if (NULL == (d->c[i] = avcodec_find_decoder(d->cc[i]->codec_id))) {
			_errstr  = "查找编码解码器失败";
			return false;
		}
        if (avcodec_open2(d->cc[i], d->c[i], NULL) < 0) {
			_errstr  = "打开编码解码器失败";
			return false;
		}

        if(!createDecodThread(d->cc[i], i))
            continue;//return false;
    }
    return true;
}

bool mediaDecode::createDecodThread(AVCodecContext* cc, int streamIndex)
{
    decodeBase *tmpDecode = NULL;
    if (AVMEDIA_TYPE_VIDEO == cc->codec_type)
         tmpDecode = new decodeVideo;

    if (!tmpDecode)
        return false;

    tmpDecode->setCodecContext(cc);
    tmpDecode->setIoQueue(d->queue);
    tmpDecode->setStreamIndex(streamIndex);
    tmpDecode->start();
    d->decode.append(tmpDecode);

    return true;
}
